﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
using System.Diagnostics;
using OpenTK;
using OpenTK.Input;
using System.Windows.Forms;

namespace Common {
    public class InputControls {

        static InputControls() {
            watch = new Stopwatch();
            watch.Start();
            lastTime = getTime();
        }
        static System.Diagnostics.Stopwatch watch;
        static double lastTime;
        static double deltaTime;
        // Initial position : on +Z
        static Vector3 position = new Vector3(0, 0, 5);
        // Initial horizontal angle : toward -Z
        static float horizontalAngle = 3.14f;
        // Initial vertical angle : none
        static float verticalAngle = 0.0f;
        // Initial Field of View
        static float initialFoV = 45.0f;

        static float speed = 3.0f; // 3 units / second
        static float mouseSpeed = 0.005f;

        public static Matrix4 ProjectionMatrix;
        public static Matrix4 ViewMatrix;

        static bool firstRun = true;
        public static void setCursorPosition(GameWindow game, Point point) {
            //Cursor.Position = point;
            var screenPoint = game.PointToScreen(point);
            Mouse.SetPosition(screenPoint.X, screenPoint.Y);
        }
        static Point getCursorPosition(GameWindow game) {

            var cursorState = Mouse.GetCursorState();
            Point cursorClientPoint = game.PointToClient(new Point(cursorState.X, cursorState.Y));
            Point mousePoint = new Point(MathHelper.Clamp(cursorClientPoint.X, 0, game.Width),
                                 MathHelper.Clamp(cursorClientPoint.Y, 0, game.Height));
            return mousePoint;
        }

        public static bool isMouseButtonDown(MouseButton button) {
            var mState=Mouse.GetState();
            return mState.IsButtonDown(button);
        }
        public static bool LockCursor = true;
        public static void computeMatricesFromInput(GameWindow game) {
            double currentTime = updateTime(game);
            float deltaTimeF = (float)(deltaTime);
            double xPos, yPos;
            xPos = getCursorPosition(game).X;
            yPos = getCursorPosition(game).Y;
            if (LockCursor) {
                setCursorPosition(game, new Point { X = game.Width / 2, Y = game.Height / 2 });
            }
            horizontalAngle += mouseSpeed * (float)(game.Width / 2 - xPos);
            verticalAngle += mouseSpeed * (float)(game.Height / 2 - yPos);

            Vector3 direction = new Vector3((float)(Math.Cos((double)verticalAngle) * Math.Sin((double)horizontalAngle)),
                (float)Math.Sin((double)verticalAngle),
                (float)(Math.Cos((double)verticalAngle) * Math.Cos((double)horizontalAngle)));

            Vector3 right = new Vector3((float)Math.Sin((double)(horizontalAngle - Math.PI / 2)),
                0,
                (float)Math.Cos((double)(horizontalAngle - Math.PI / 2)));

            Vector3 up = Vector3.Cross(right, direction);

            var keystate = OpenTK.Input.Keyboard.GetState();
            if (keystate[Key.Up]) {
                position += direction * deltaTimeF * speed;
            }
            else if (keystate[Key.Down]) {
                position -= direction * deltaTimeF * speed;
            }
            else if (keystate[Key.Right]) {
                position += right * deltaTimeF * speed;
            }
            else if (keystate[Key.Left]) {
                position -= right * deltaTimeF * speed;
            }
            else if (keystate[Key.Escape]) {
                game.Exit();
            }
            float Fov = initialFoV;

            ProjectionMatrix = Matrix4.CreatePerspectiveFieldOfView((float)Math.PI * Fov / 180.0f, 4.0f / 3.0f, 0.1f, 100.0f);
            ViewMatrix = Matrix4.LookAt(position, position + direction, up);

        }

        public static double updateTime(GameWindow game) {
            if (firstRun) {
                lastTime = getTime();
                firstRun = false;
                setCursorPosition(game, new Point { X = game.Width / 2, Y = game.Height / 2 });
            }

            double currentTime = getTime();
            deltaTime = currentTime - lastTime;
            lastTime = currentTime;

            return currentTime;
        }

        public static double getDeltaTime() {
            return deltaTime;
        }
        public static double getTime() {
            return ((double)watch.ElapsedTicks) / TimeSpan.TicksPerSecond;
        }
    }
}
